<!DOCTYPE html>
<html>

<head>
  <title>canvas test-25 - 像素级别碰撞检测</title>
  <style type="text/css">
  * {
    margin: 0;
    padding: 0
  }
  
  pre {
    padding: 10px 0
  }
  </style>
</head>

<body>
  <pre>
    像素级别的碰撞检测原理

      将待检测的两个图形采用单色求交集绘制到缓存的canvas上，检测canvas像素中是否包含有alpha通道是否不为透明像素时即发生碰撞

      利用ctx.globalCompositeOperation = 'source-in'对两个图形求交集

    像素级别的碰撞检测适用于任意图形，但性能不高，可以采用包围盒方式检测求出相交矩形区域，仅仅检测该矩形区域像素来优化性能, 后面将对该方法进行优化
  </pre>
  <p></p>
  <canvas id="stage" width="400" height="300" style="border: 1px solid red; margin: 20px"></canvas>
  <script src="raf.js"></script>
  <script src="vector2.js"></script>
  <script src="resource.js"></script>
  <script type="text/javascript">
  var canvas = document.getElementById('stage');
  var ctx = canvas.getContext('2d');
  var hitCanvas = document.createElement('canvas');
  var hitCtx = hitCanvas.getContext('2d');
  hitCanvas.width = canvas.width;
  hitCanvas.height = canvas.height;

  var PI2 = Math.PI * 2;
  var ARC = Math.PI / 180;
  var fillColor = 'blue';
  var lastTime = 0;
  var obj1, obj2, ticker;

  window.onload = init;

  function init() {
    obj1 = new Rect(new Vector2(100, 100), new Vector2(50, 80), 50);
    // obj2 = new Rect( new Vector2(180, 100), new Vector2(40, 80), -210 );
    obj2 = new Polygon(
      new Vector2(140, 110),
      new Vector2(270, 50),
      new Vector2(270, 140),
      new Vector2(220, 160),
      new Vector2(140, 140),
      0
    );
    ticker = window.requestAnimationFrame(rendering);
  }

  function rendering(ts) {
    var t = lastTime ? ts - lastTime : 0;
    lastTime = ts;
    ctx.clearRect(0, 0, canvas.width + 1, canvas.height + 1);
    obj1.update(t);
    obj2.update(t * 1.1);
    var collied = testCollision();
    fillColor = collied ? 'red' : 'blue';
    obj1.draw(ctx);
    obj2.draw(ctx);
    window.requestAnimationFrame(rendering);
  }

  function testCollision() {
    hitCtx.clearRect(0, 0, canvas.width, canvas.height);
    obj1.draw(hitCtx, '#ff0000');
    hitCtx.save();
    hitCtx.globalCompositeOperation = 'source-in';
    obj2.draw(hitCtx, '#ff0000');
    hitCtx.restore();
    var imgdata = hitCtx.getImageData(0, 0, canvas.width, canvas.height).data;
    for (var i = 0, l = imgdata.length; i < l; i += 4) {
      if (imgdata[i + 3] > 0) {
        return true;
      }
    }
    return false;
  }

  function Rect(pos, size, deg) {
    this.pos = pos;
    this.size = size;
    this.deg = (deg || 0) * ARC;
    this.rot = ARC;
  }

  Rect.prototype.update = function(ts) {
    this.deg += ARC * ts / 10;
  };

  Rect.prototype.render = function(ctx, fillStyle) {
    ctx.fillStyle = fillStyle || fillColor;
    ctx.translate(this.pos.x, this.pos.y);
    ctx.rotate(this.deg);
    ctx.fillRect(-this.size.x / 2, -this.size.y / 2, this.size.x, this.size.y);
  };

  Rect.prototype.draw = function(ctx, fillStyle) {
    ctx.save();
    this.render(ctx, fillStyle);
    ctx.restore();
  };


  function Polygon( /*point1,ponit2,...,deg*/ ) {
    var args = Array.prototype.slice.call(arguments);
    this.deg = args.pop();
    this.rot = ARC;
    this.points = args;
    // 计算多边形重心
    var x = 0;
    var y = 0;
    var len = args.length;
    this.points.forEach(function(point) {
      x += point.x;
      y += point.y;
    });
    this.centerPoint = new Vector2(x / len, y / len);
  }

  Polygon.prototype.update = function(ts) {
    this.deg += ARC * ts / 10;
  };

  Polygon.prototype.render = function(ctx, fillStyle) {
    var c = this.centerPoint;
    ctx.fillStyle = fillStyle || fillColor;
    ctx.translate(c.x, c.y);
    ctx.rotate(this.deg);
    ctx.beginPath();
    this.points.forEach(function(point) {
      ctx.lineTo(point.x - c.x, point.y - c.y);
    });
    ctx.closePath();
    ctx.fill();
  };

  Polygon.prototype.draw = function(ctx, fillStyle) {
    ctx.save();
    this.render(ctx, fillStyle);
    ctx.restore();
  };
  </script>
</body>

</html>
